package com.wyz.mybatislogtosql;
import java.io.*;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 业务逻辑
 */
public abstract class MyBatisLogToSqlUtils {

    public static String convert(String[] logs,String filterText) {
        if (logs.length >= 2) {
            Map<String,SqlModel> sqlStrMap = new HashMap<>();
            StringWriter writer  = new StringWriter();
            for (String log : logs) {
                writer.write(handleOneRow(sqlStrMap, log, filterText));
            }
            sqlStrMap.values().forEach(o->  writer.write(convertSql(o)));
            return writer.toString();
        }
        return "日志格式不正确";
    }

    public static void handleLogFile(File sourceFile,File targetFile,String filterText){
        if (!sourceFile.exists()){
            throw new RuntimeException("源文件不存在");
        }
        if (!targetFile.exists()){
            try {
                targetFile.createNewFile();
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage());
            }
        }
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        try {
            bufferedReader = new BufferedReader(new FileReader(sourceFile));
            bufferedWriter = new BufferedWriter(new FileWriter(targetFile));

            String s;
            Map<String,SqlModel> sqlStrMap = new HashMap<>();
            while ((s=bufferedReader.readLine())!=null){
                bufferedWriter.write(handleOneRow(sqlStrMap,s, filterText));
            }
            Iterator<SqlModel> iterator = sqlStrMap.values().iterator();
            while (iterator.hasNext()){
                bufferedWriter.write(convertSql(iterator.next()));
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
        finally {
            if (bufferedReader!=null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    throw new RuntimeException(e.getMessage());
                }
            }
            if (bufferedWriter!=null){
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    throw new RuntimeException(e.getMessage());
                }
            }
        }

    }


    static boolean isMatch(String sourceStr, String filterStr){
        return Pattern.matches(filterStr, sourceStr);
    }

    static String handleOneRow( Map<String,SqlModel> sqlStrMap,String log,String filterText){
        String thread = getThread(log);
        SqlModel sqlModel  = sqlStrMap.get(thread);
        String preparing = getPreparing(log);
        String s = "";
        if (preparing != null) {
            s = convertSql(sqlModel);
            if (isMatch(preparing,filterText)){
                sqlStrMap.put(thread,new SqlModel(preparing,new LinkedList<>()));
            } else {
                sqlStrMap.remove(thread);
            }
        }
        else if (sqlModel!=null){
            String  parameters = getParameters(log);
            if (parameters!=null){
                sqlModel.parameters.add(parameters);
            }
        }
        return s;
    }

    static String getThread(String  str){
        String pattern = "\"thread\": ";
        int parIndex = str.indexOf(pattern);
        if (parIndex != -1) {
            int i = str.indexOf("\"",parIndex+pattern.length());
            int i1 = str.indexOf("\"", i+1);
            return str.substring(i+1,i1);
        }
        return null;
    }

    static String getPreparing(String str){
        return indexOf(str, "==>  Preparing: ");
    }

    static String getParameters(String str){
        return indexOf(str, "==> Parameters: ");
    }

    static String convertSql(SqlModel sqlModel) {
        if (sqlModel==null){
            return "";
        }
        StringBuilder builder = new StringBuilder();
        for (String parameter : sqlModel.parameters) {
            List<Param> params = parseParam(parameter);
            Iterator<Param> iterator = params.iterator();
            int start = 0;
            int end = sqlModel.preparing.length();
            while (start < end) {
                char c = sqlModel.preparing.charAt(start);
                if (c == '?') {
                    if (iterator.hasNext()) {
                        Param param = iterator.next();
                        if (param.type.startsWith("Integer") || param.type.startsWith("Long")) {
                            builder.append(param.value);
                        } else {
                            builder.append('\'');
                            builder.append(param.value);
                            builder.append('\'');
                        }
                    } else {
                        throw new IllegalArgumentException("参数个数不匹配");
                    }
                } else {
                    builder.append(c);
                }
                start++;
            }
            builder.append(";\n");
        }
        return builder.toString();
    }




    static String indexOf(String str, String pattern) {
        int parIndex = str.indexOf(pattern);
        if (parIndex != -1) {
            int i = str.lastIndexOf("\"stack_trace\"");
            int i1 = str.lastIndexOf("\"", i-1);
            return str.substring(parIndex + pattern.length(),i1);
        }
        return null;
    }


    static List<Param> parseParam(String log) {
        List<Param> result = new ArrayList<Param>();
        String[] split = log.split("\\),");

        for (String s : split) {
            s = s.trim();
            while(s.startsWith("null")){
                result.add( new Param("null","Integer"));
                s = s.substring(4);
                s = s.trim();
                if (s.startsWith(",")){
                    s=s.substring(1);
                    s = s.trim();
                }
            }
            int i = s.lastIndexOf("(");
            if (i!=-1){
                String type = s.substring(i+1);
                String value = s.substring(0,i);
                result.add( new Param(value,type));
            }
        }
        return result;
    }

    static class Param {

        final String type;
        final String value;

        public Param(String value, String type) {
            this.type = type;
            this.value = value;
        }
    }

    static class SqlModel {

        final String preparing;
        final List<String> parameters;

        public SqlModel(String preparing, List<String> parameters) {
            this.preparing = preparing;
            this.parameters = parameters;
        }

    }

}